#include <iostream>
#include <fstream>
#include <string.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include "shader.h"

using namespace std;


/*
 * Returns a string containing the text in
 * a vertex/fragment shader source file.
 */
static string
shaderLoadSource(const char *filePath)
{
	std::string source("");

	ifstream in(filePath, std::ios::in);
	if (in) {
		while(!in.eof()) {
			source.push_back(in.get());
		}
	} else {
		std::cerr << "shaderLoadSource(): Unable to open " << filePath << " for reading." << endl;
	}
	return source;
}

/*
 * Returns a shader object containing a shader
 * compiled from the given GLSL shader file.
 */
static GLuint
shaderCompileFromFile(GLenum type, const char *filePath)
{
	string source;
	GLuint shader;
	GLint  length, result;

	/* get shader source */
	source = shaderLoadSource(filePath);
	if(source.empty())
		return 0;

	/* create shader object, set the source, and compile */
	shader = glCreateShader(type);
	length = source.length();
	const char* p = &source[0];
	glShaderSource(shader, 1, (const char**)&p, &length);
	glCompileShader(shader);
	source.clear();

	/* make sure the compilation was successful */
	glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
	if(result == GL_FALSE) {
		std::string log("");
		/* get the shader info log */
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
		glGetShaderInfoLog(shader, length, &result, &log[0]);

		/* print an error message and the info log */
		std::cerr << "shaderCompileFromFile(): Unable to compile " << filePath << ": " <<  log;
		log.clear();

		glDeleteShader(shader);
		return 0;
	}

	return shader;
}

/*
 * Compiles and attaches a shader of the
 * given type to the given program object.
 */
void
shaderAttachFromFile(GLuint program, GLenum type, const char *filePath)
{
	/* compile the shader */
	GLuint shader = shaderCompileFromFile(type, filePath);
	if(shader != 0) {
		/* attach the shader to the program */
		glAttachShader(program, shader);

		/* delete the shader - it won't actually be
		 * destroyed until the program that it's attached
		 * to has been destroyed */
		glDeleteShader(shader);
	}
}
